#include <stdlib.h>
#include "base/core/json_parser.h"
#include "base/core/log.h"
#include "../../../source/core/json/yajl/yajl_tree.h"

JsonValue::JsonValue() 
{
	Reset();
}  

JsonValue::~JsonValue() 
{
	Reset();
}

JsonValue& JsonValue::operator[](const int idx) 
{
	if (val_type_ != TYPE_ARRAY) 
	{
		LogErrFmtPrint("type:%d, is not array", val_type_);
		throw "error not vec_type";
	}
	int size = static_cast<int>(vec_val_.size());
	if (idx >= size) 
	{
		LogErrFmtPrint("array_size:%d, get_idx:%d", size, idx);
		throw "idx to large";
	}
	return vec_val_[idx];
}

JsonValue& JsonValue::operator[](const char* key) 
{
	if (val_type_ != TYPE_MAP) 
	{
		LogErrFmtPrint("type:%d, is not map", val_type_);
		throw "error not map_type";
	}
	ValMap::iterator it = map_val_.find(key);
	if (it == map_val_.end()) 
	{
		LogErrFmtPrint("map_size:%lu, can't find key:%s", map_val_.size(), key);
		throw "map can't find key";
	}
	return it->second;
}

size_t JsonValue::size() 
{
    if (val_type_ == TYPE_ARRAY) 
	{
        return vec_val_.size();
    }
    if (val_type_ == TYPE_MAP) {
        return map_val_.size();
    }
    LogErrPrint("JsonValue::size:error type ");
    return 0;
}

bool JsonValue::HasKey(const char* key) 
{
	ValMap::iterator it = map_val_.find(key);
	if (it == map_val_.end()) 
	{
		return false;
	}
	return true;
}

string JsonValue::ToString() 
{
	if (val_type_ == TYPE_BOOL ||
		val_type_ == TYPE_DOUBLE ||
		val_type_ == TYPE_LONG ||
		val_type_ == TYPE_STR) 
	{
		return str_val_;
	} 
	else if (val_type_ == TYPE_ARRAY) 
	{
		if (vec_val_.size() == 1) 
		{
			return vec_val_[0].ToString();
		}
	}
	LogErrFmtPrint("type:%d, can't ToString", val_type_);
	throw "ToString error";
}

int64_t JsonValue::ToLong() 
{
	if (val_type_ == TYPE_LONG) 
	{
		return unn_val_.l;
	} 
	else if(val_type_ == TYPE_DOUBLE) 
	{
		return strtoull(str_val_.c_str(), nullptr, 10);
	} 
	else if(val_type_ == TYPE_STR) 
	{
		return strtoull(str_val_.c_str(), nullptr, 10);
	} 
	else if (val_type_ == TYPE_ARRAY)
	{
		if (vec_val_.size() == 1) 
		{
			return vec_val_[0].ToLong();
		}
	}
	LogErrFmtPrint("type:%d, can't ToLong", val_type_);
	throw "ToLong error";
}

double JsonValue::ToDouble() 
{
	if (val_type_ == TYPE_DOUBLE) 
	{
		return unn_val_.d;
	} 
	else if(val_type_ == TYPE_LONG) 
	{
		return atof(str_val_.c_str());
	} 
	else if(val_type_ == TYPE_STR) 
	{
		return atof(str_val_.c_str());
	} 
	else if (val_type_ == TYPE_ARRAY) 
	{
		if (vec_val_.size() == 1) 
		{
			return vec_val_[0].ToDouble();
		}
	}
	LogErrFmtPrint("type:%d, can't ToDouble", val_type_);
	throw "ToDouble error";
}

bool JsonValue::ToBool() 
{
	if (val_type_ == TYPE_BOOL) 
	{
		return unn_val_.b;
	} 
	else if (val_type_ == TYPE_ARRAY) 
	{
		if (vec_val_.size() == 1) 
		{
			return vec_val_[0].ToBool();
		}
	}
	LogErrFmtPrint("type:%d, can't ToBool", val_type_);
	throw "ToBool error";
}

bool JsonValue::IsValid() 
{
    return val_type_ != TYPE_NONE;
}

void JsonValue::Reset() 
{
	vec_val_.clear();
	map_val_.clear();
	val_type_ = TYPE_NONE;
}

void JsonValue::SetValue(void* y_val) 
{
	yajl_val node = reinterpret_cast<yajl_val>(y_val);
	if (YAJL_IS_ARRAY(node)) 
	{
		val_type_ = TYPE_ARRAY;
		vec_val_.resize(node->u.array.len);
		for (size_t i = 0; i < node->u.array.len; i++) 
		{
			yajl_val  obj = node->u.array.values[i];      
			vec_val_[i].SetValue(obj);
		}
	} 
	else if (YAJL_IS_OBJECT(node)) 
	{
		val_type_ = TYPE_MAP;
		for (size_t i = 0; i < node->u.object.len; i++) 
		{
			yajl_val    v = node->u.object.values[i];
			const char* k = node->u.object.keys[i];
			map_val_[k].SetValue(v);
		}
	} 
	else if (YAJL_IS_INTEGER(node)) 
	{
		SetLong(node->u.number.i);
	} 
	else if (YAJL_IS_DOUBLE(node)) 
	{
		SetDouble(node->u.number.d);
	} 
	else if (YAJL_IS_FALSE(node) || YAJL_IS_TRUE(node)) 
	{
		SetBool(YAJL_IS_TRUE(node) ? true: false);
	} 
	else if (YAJL_IS_STRING(node)) 
	{
		SetStr(node->u.string);
	}
}

void JsonValue::SetStr(char* str) 
{
	val_type_ = TYPE_STR;
	str_val_ = string(str);
}

void JsonValue::SetBool(bool b) 
{
	val_type_ = TYPE_BOOL;
	unn_val_.b = b;
	char str[64];
	memset(str, 0, sizeof(str));
	snprintf(str, sizeof(str), "%s", b ? "true" : "false");
	str_val_ = string(str);
}

void JsonValue::SetDouble(double d) 
{
	val_type_ = TYPE_DOUBLE;
	unn_val_.d = d;
	char str[64];
	memset(str, 0, sizeof(str));
	snprintf(str, sizeof(str), "%lf", unn_val_.d);
	str_val_ = string(str);
}

void JsonValue::SetLong(int64_t l) 
{
	val_type_ = TYPE_LONG;
	unn_val_.l = l;
	char str[64];
	memset(str, 0, sizeof(str));
#ifdef _MSC_VER
	snprintf(str, sizeof(str), "%lld", unn_val_.l);
#endif 

#ifdef OS_LINUX
	snprintf(str, sizeof(str), "%ld", unn_val_.l);
#endif
	str_val_ = string(str);
}

// JsonParser
bool JsonParser::Parse(const char* json_str, JsonValue* val) 
{
	val->Reset();
	char errbuf[1024];
	yajl_val node = yajl_tree_parse(json_str, errbuf, sizeof(errbuf));
	if (node == NULL)
	{
		LogErrFmtPrint("parse json error:%s", errbuf);
		return false;
	}
	val->SetValue(node);
	yajl_tree_free(node);
	return true;
}
